use std::collections::HashMap;

use tracing::info;

use bc_base::{BlockId, block::Block};

#[derive(Debug)]
pub(super) struct OrphanBlocks {
    orphan_blocks: HashMap<BlockId, Block>,
    orphan_blocks_by_prev: HashMap<BlockId, Vec<BlockId>>, // <prev-block-id, child-blocks>
}

impl OrphanBlocks {
    pub fn new() -> Self {
        Self {
            orphan_blocks: HashMap::new(),
            orphan_blocks_by_prev: HashMap::new(),
        }
    }

    pub fn contains(&self, block_id: &BlockId) -> bool {
        self.orphan_blocks.contains_key(block_id)
    }

    pub fn get_orphan_block(&self, block_id: &BlockId) -> Option<&Block> {
        self.orphan_blocks.get(block_id)
    }

    pub fn add_orphan_block(&mut self, block_id: &BlockId, block: &Block, prev_block_id: &BlockId) {
        info!("Orphan Block, prev block id = {}", prev_block_id);
        self.orphan_blocks.insert(*block_id, block.clone());

        let prev_block_id_key = *prev_block_id;
        if let Some(blocks) = self.orphan_blocks_by_prev.get_mut(&prev_block_id_key) {
            blocks.push(*block_id);
        } else {
            self.orphan_blocks_by_prev
                .insert(prev_block_id_key, vec![*block_id]);
        }
    }

    pub fn remove_orphan_block(&mut self, block_id: &BlockId) -> Option<Block> {
        self.orphan_blocks.remove(block_id)
    }

    pub fn remove_orphan_block_by_prev(&mut self, prev_block_id: &BlockId) -> Option<Vec<BlockId>> {
        self.orphan_blocks_by_prev.remove(prev_block_id)
    }
}
